package ui;

import cmm.CMMLexer;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.*;
import java.awt.*;

public class SyntaxHighlighter implements DocumentListener {
    private CMMLexer lexer;
    private Style keywordStyle;
    private Style numberStyle;
    private Style typeStyle;
    private Style identityStyle;
    private Style normalStyle;
    private Editor cmmEditor;

    public SyntaxHighlighter(JTextPane editor,Editor cmmEditor){
        //准备着色使用的样式
        keywordStyle=((StyledDocument)editor.getDocument()).addStyle("Identity_Style",null);
        numberStyle=((StyledDocument)editor.getDocument()).addStyle("Number_Style",null);
        typeStyle=((StyledDocument)editor.getDocument()).addStyle("Type_Style",null);
        identityStyle=((StyledDocument)editor.getDocument()).addStyle("Identity_Style",null);
        normalStyle=((StyledDocument)editor.getDocument()).addStyle("Normal_Style",null);

        StyleConstants.setForeground(keywordStyle, new Color(0x000080));
        StyleConstants.setForeground(numberStyle, new Color(0x0000FF));
        StyleConstants.setForeground(typeStyle, new Color(0x000080));
        StyleConstants.setForeground(identityStyle, new Color(0x660E7A));
        StyleConstants.setForeground(normalStyle, Color.BLACK);

        this.cmmEditor=cmmEditor;
    }

    private void coloring(StyledDocument doc) throws BadLocationException {
        lexer = new CMMLexer(CharStreams.fromString(doc.getText(0, doc.getLength())));
        Token token;
        while ((token = lexer.nextToken()).getType() != -1) {
            int startIndex = token.getStartIndex();
            int stopIndex = token.getStopIndex();
            String type = lexer.typeTransfer(token.getType());
            if (type.equals("KeyWord")) {
                SwingUtilities.invokeLater(new ColouringTask(doc, startIndex, stopIndex - startIndex + 1, keywordStyle));
            } else if (type.equals("Number")) {
                SwingUtilities.invokeLater(new ColouringTask(doc, startIndex, stopIndex - startIndex + 1, numberStyle));
            } else if (type.equals("Type")) {
                SwingUtilities.invokeLater(new ColouringTask(doc, startIndex, stopIndex - startIndex + 1, typeStyle));
            } else if (type.equals("Variable")) {
                SwingUtilities.invokeLater(new ColouringTask(doc, startIndex, stopIndex - startIndex + 1, identityStyle));
            } else {
                SwingUtilities.invokeLater(new ColouringTask(doc, startIndex, stopIndex - startIndex + 1, normalStyle));
            }
        }
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
//        cmmEditor.lineNumRelist();
//        cmmEditor.lineNumReset(e.getOffset(), true);
//        e.getChange(e.)
        cmmEditor.lineNumReset();
        cmmEditor.titleReset();
        try {
            coloring((StyledDocument)e.getDocument());
        } catch (BadLocationException e1) {
            e1.printStackTrace();
        }
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
//        cmmEditor.lineNumRelist();

        cmmEditor.lineNumReset();
        cmmEditor.titleReset();
        try {
            coloring((StyledDocument)e.getDocument());
        } catch (BadLocationException e1) {
            e1.printStackTrace();
        }
    }

    @Override
    public void changedUpdate(DocumentEvent e) {

    }

    /**
     * 完成着色任务
     *
     */
    private class ColouringTask implements Runnable {
        private StyledDocument doc;
        private Style style;
        private int pos;
        private int len;

        public ColouringTask(StyledDocument doc, int pos, int len, Style style) {
            this.doc = doc;
            this.pos = pos;
            this.len = len;
            this.style = style;
        }

        public void run() {
            try {
                // 这里就是对字符进行着色
                doc.setCharacterAttributes(pos, len, style, true);
            } catch (Exception e) {
            }
        }
    }
}
